本篇文章將針對 HTTP 協定進行深入探討,並設計實作實驗(lab)來幫助讀者更好地理解這個重要的網路協定。
文章將涵蓋以下三個關鍵主題:
想像一下,HTTP 請求方法就像是你在餐廳點餐時,對服務生說的不同指令。
每種方法都有特定的用途,就像你點不同的菜一樣。以下是常見 HTTP 方法的簡單解釋:
// routes/httpHandlers.js
// 處理所有 HTTP 方法的路由
app.all('/method', (req, res) => {
const method = req.method;
res.send(`The HTTP method used was: ${method}`);
});
const { handleMethod } = require('./routes/httpHandlers');
// 處理所有 HTTP 方法的路由
app.all('/method', handleMethod);
app.all()
方法如何處理所有類型的 HTTP 請求。curl -X [HTTP_METHOD] [URL]
其中,[HTTP_METHOD]
是你想要使用的 HTTP 方法,[URL]
是你要請求的網址。
curl http://nodelab.feifei.tw/method/api/resource
GET 是預設的方法,所以不需要 -X
參數。
curl -X POST -d "param1=value1¶m2=value2" http://nodelab.feifei.tw/method/api/resource
-d
參數用來發送 POST 資料。
curl -X PUT -d "param1=value1¶m2=value2" http://nodelab.feifei.tw/method/api/resource
curl -X DELETE http://nodelab.feifei.tw/method/api/resource
curl -X PATCH -d "param1=value1" http://nodelab.feifei.tw/method/api/resource
curl -I http://nodelab.feifei.tw/method
-I
參數相當於發送 HEAD 請求。
curl -X OPTIONS http://nodelab.feifei.tw/method
HTTP 狀態碼是伺服器對客戶端請求的回應,用於表示請求處理的結果。了解這些狀態碼有助於我們判斷請求的處理情況,並找出潛在的問題。
HTTP 狀態碼分為五類,每類都有其特定的意義:
在開發 Web 應用時,正確使用 HTTP 狀態碼可以:
// routes/httpHandlers.js
app.all('/status/:code', (req, res) => {
const code = parseInt(req.params.code);
const message = getStatusMessage(code);
res.status(code).json({ code, message });
});
// 輔助函數:取得狀態碼對應的訊息
function getStatusMessage(code) {
const messages = {
// 1xx 訊息
100: '繼續處理中',
101: '切換協定',
102: '處理中', // RFC 2518 WebDAV 擴充
// 2xx 成功
200: '請求成功',
201: '資源已建立',
202: '已接受處理,但尚未完成',
204: '無內容,無需回應',
206: '部分內容', // 針對範圍請求
// 3xx 重定向
300: '多種選擇',
301: '資源永久移動',
302: '資源暫時移動',
303: '請查看其他位置',
304: '資源未修改',
307: '暫時重定向',
308: '永久重定向',
// 4xx 客戶端錯誤
400: '錯誤的請求',
401: '未授權,請登入',
403: '禁止存取',
404: '找不到資源',
405: '不允許的請求方法',
406: '不接受的回應格式',
408: '請求超時',
409: '資源衝突',
410: '資源已永久移除',
429: '請求次數過多,請稍後再試',
// 5xx 伺服器錯誤
500: '伺服器內部錯誤',
501: '功能尚未實作',
502: '錯誤的網關',
503: '服務目前無法使用',
504: '網關超時',
505: '不支援的 HTTP 版本'
};
return messages[code] || '未知的狀態碼';
}
const { handleMethod, handleStatus } = require('./routes/httpHandlers');
// 處理所有 HTTP 方法的路由
app.all('/method', handleMethod);
// 狀態碼處理路由
app.all('/status/:code', handleStatus);
curl -i http://nodelab.feifei.tw/status/404
HTTP 標頭是請求和回應中不可或缺的一部分,它們攜帶了關於傳輸、安全性、內容類型等重要資訊。然而,某些標頭可能會洩露敏感資訊,如伺服器版本,這些資訊可能被惡意使用者利用來進行攻擊。
在身分驗證的環境中,HTTP 標頭再次扮演了關鍵角色,特別是在基本認證(Basic Authentication)的實現中。
身分驗證是網站安全的核心環節之一,用於驗證使用者的身分,並根據其權限授予對應的資源訪問權。
每種方法都有其優缺點和適用場景。在實際應用中,常常會結合多種方法來增強安全性並改善使用者體驗。選擇合適的驗證方式需要考慮安全需求、使用者友善度、技術實作難度等多個因素。
身分驗證是確保系統安全的重要環節。在 Web 應用程式中,基本認證是一種簡單但廣泛使用的方法。
// routes/authHandler.js
// 模擬的使用者資料庫,實際應用中應該從資料庫查詢
const users = {
'admin': 'password123',
'user': 'userpass'
};
function authenticateBasic(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader) {
res.setHeader('WWW-Authenticate', 'Basic realm="Restricted Area"');
return res.status(401).send('認證失敗:需要提供認證資訊。');
}
const auth = Buffer.from(authHeader.split(' ')[1], 'base64').toString().split(':');
const user = auth[0];
const pass = auth[1];
if (users[user] && users[user] === pass) {
next();
} else {
res.setHeader('WWW-Authenticate', 'Basic realm="Restricted Area"');
return res.status(401).send('認證失敗:使用者名稱或密碼錯誤。');
}
}
// 受保護的路由處理器
function protectedRoute(req, res) {
res.send('歡迎來到受保護的區域!');
}
module.exports = {
authenticateBasic,
protectedRoute
};
模擬使用者資料庫:
const users = {
'admin': 'password123',
'user': 'userpass'
};
這是一個簡單的物件,用於模擬使用者資料庫。在實際應用中,這應該被替換為真實的資料庫查詢。
authenticateBasic 函數:
這是一個 Middleware 函數,用於處理基本認證。
檢查授權標頭:
const authHeader = req.headers.authorization;
從請求標頭中取得 Authorization
欄位。
處理未提供認證資訊的情況:
if (!authHeader) {
res.setHeader('WWW-Authenticate', 'Basic realm="Restricted Area"');
return res.status(401).send('認證失敗:需要提供認證資訊。');
}
如果沒有提供認證資訊,設定 WWW-Authenticate
標頭並返回 401 狀態碼。
解碼和驗證認證資訊:
const auth = Buffer.from(authHeader.split(' ')[1], 'base64').toString().split(':');
const user = auth[0];
const pass = auth[1];
解碼 base64 編碼的認證資訊,並分離使用者名稱和密碼。
驗證使用者:
if (users[user] && users[user] === pass) {
next();
} else {
res.setHeader('WWW-Authenticate', 'Basic realm="Restricted Area"');
return res.status(401).send('認證失敗:使用者名稱或密碼錯誤。');
}
檢查使用者名稱和密碼是否相同。如果相同,調用 next()
繼續處理請求;否則,返回 401 錯誤。
const { authenticateBasic, protectedRoute } = require('./routes/authHandler');
// 設定受保護的路由
app.get('/protected', authenticateBasic, protectedRoute);
這段程式碼將 authenticateBasic
Middleware 應用到 /protected
路由,確保只有通過認證的使用者才能訪問。
http://nodelab.feifei.tw/protected
curl -v http://nodelab.feifei.tw/protected
curl -H
指定標頭curl -H "Authorization: Basic YWRtaW46cGFzc3dvcmQxMjM=" -v http://nodelab.feifei.tw/protected
YWRtaW46cGFzc3dvcmQxMjM=
Base64 是一種用來將二進位資料轉換成文字的編碼方式,主要使用 64 個可列印的字元來表示資料,這使得資料可以安全地在需要純文字傳輸的環境中傳送(例如在 URL、電子郵件等情況下)。
Base64 是一種將數位資料編碼成文字的技術。你可以把它想像成一個翻譯器,它把電腦使用的 0 和 1(也就是位元資料)轉換成我們能夠閱讀的字母和符號。
Base64 編碼的基本原理是:
當需要編碼的資料長度不是 3 的倍數時,Base64 會在結果中加上等號來表示這個資料的結尾。這樣可以確保編碼結果是完整且準確的。
這樣的方式可以幫助資料在不同系統之間傳輸時保持一致性,並且避免因為某些系統只接受文字格式而產生的問題。
HTTP 請求方法中,哪一種方法適合用來提交敏感資料?
答案: B) POST
哪一個狀態碼代表請求成功?
答案: C) 200
在基本驗證中,使用者的帳號和密碼是如何傳送的?
答案: B) Base64 編碼
HTTP 請求方法中,哪一種方法用於查詢伺服器支援的 HTTP 方法?
答案: A) OPTIONS
以下哪一項是 Base64 編碼的特徵?
答案: C) 最後可能出現一個或兩個等號
httpHandlers.js
,處理所有 HTTP 方法。app.all('/method', handleMethod)
接收請求並回應使用的請求方法。curl
測試請求
curl http://nodelab.feifei.tw/method
curl -X POST -d "param1=value1¶m2=value2" http://nodelab.feifei.tw/method
curl -X PUT -d "param1=value1¶m2=value2" http://nodelab.feifei.tw/method
curl -X DELETE http://nodelab.feifei.tw/method
curl -X PATCH -d "param1=value1" http://nodelab.feifei.tw/method
curl -I http://nodelab.feifei.tw/method
curl -X OPTIONS http://nodelab.feifei.tw/method
httpHandlers.js
以處理狀態碼請求。curl -i http://nodelab.feifei.tw/status/404
測試。authHandler.js
中實作基本驗證。app.get('/protected', authenticateBasic, protectedRoute);